package com.ctd.springframework.util;

import java.util.*;

/**
 * StringUtils
 *
 * @author chentudong
 * @time 2019/3/24 14:59
 */
public class StringUtils {
    private static final String FOLDER_SEPARATOR = "/";
    private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
    private static final String TOP_PATH = "..";
    private static final String CURRENT_PATH = ".";

    /**
     * clean
     *
     * @param path path
     * @return String
     */
    public static String cleanPath(String path) {
        //path == null || path = ""
        if (!hasLength(path)) {
            return path;
        }
        //replace
        String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);
        //indexOf ':'
        int prefixIndex = pathToUse.indexOf(':');
        String prefix = "";
        if (prefixIndex != -1) {
            // pathToUse = classpath:mynean.xml replace to prefixIndex +1  prefix = classpath:
            prefix = pathToUse.substring(0, prefixIndex + 1);
            // is contains / , this is true: prefix = "";
            if (prefix.contains(FOLDER_SEPARATOR)) {
                prefix = "";
            } else {
                //substring()  pathToUse = mybean.xml
                pathToUse = pathToUse.substring(prefixIndex + 1);
            }
        }
        //is pathToUse  startsWith ('/')
        if (pathToUse.startsWith(FOLDER_SEPARATOR)) {
            prefix = prefix + FOLDER_SEPARATOR;
            pathToUse = pathToUse.substring(1);
        }
        String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);
        LinkedList<String> pathElements = new LinkedList<>();
        int tops = 0;
        for (int i = pathArray.length - 1; i >= 0; i--) {
            String element = pathArray[i];
            if (CURRENT_PATH.equals(element)) {
            } else if (TOP_PATH.equals(element)) {
                tops++;
            } else {
                if (tops > 0) {
                    tops--;
                } else {
                    pathElements.add(0, element);
                }
            }
        }
        //add 0 is  ..
        for (int i = 0; i < tops; i++) {
            pathElements.add(0, TOP_PATH);
        }
        if ((pathElements.size() == 1) && ("".equals(pathElements.getLast())) && (!prefix.endsWith(FOLDER_SEPARATOR))) {
            pathElements.add(0, CURRENT_PATH);
        }
        //prefix + (pathElements is FOLDER_SEPARATOR toString)
        return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);
    }

    /**
     * for coll  this is coll = [com, ctd, mybean.xml] , delim = / change com/ctd/mybean.xml
     *
     * @param coll  coll
     * @param delim delim
     * @return String
     */
    public static String collectionToDelimitedString(Collection<?> coll, String delim) {
        return collectionToDelimitedString(coll, delim, "", "");
    }

    /**
     * for coll this is prefix + next + suffix
     * bug next is not null this is prefix + next + suffix + delim
     *
     * @param coll   coll
     * @param delim  delim
     * @param prefix prefix
     * @param suffix suffix
     * @return String
     */
    public static String collectionToDelimitedString(Collection<?> coll, String delim, String prefix, String suffix) {
        if (CollectionUtils.isEmpty(coll)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        Iterator<?> it = coll.iterator();
        while (it.hasNext()) {
            sb.append(prefix).append(it.next()).append(suffix);
            if (it.hasNext()) {
                sb.append(delim);
            }
        }
        return sb.toString();
    }

    /**
     * delete str indexOf delimiter string  str to array
     *
     * @param str       str
     * @param delimiter delimiter
     * @return String[]
     */
    public static String[] delimitedListToStringArray(String str, String delimiter) {
        return delimitedListToStringArray(str, delimiter, null);
    }

    /**
     * string to array
     *
     * @param str           str
     * @param delimiter     delimiter
     * @param charsToDelete charsToDelete
     * @return String[]
     */
    public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
        if (Objects.isNull(str)) {
            return new String[0];
        }
        if (Objects.isNull(delimiter)) {
            return new String[]{str};
        }
        List<String> result = new ArrayList<>();
        // delimiter is ""
        if (delimiter.isEmpty()) {
            for (int i = 0; i < str.length(); i++) {
                result.add(deleteAny(str.substring(i, i + 1), charsToDelete));
            }
        } else {
            int pos = 0;
            int delPos;
            while ((delPos = str.indexOf(delimiter, pos)) != -1) {
                result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
                pos = delPos + delimiter.length();
            }
            if ((!str.isEmpty()) && (pos <= str.length())) {
                result.add(deleteAny(str.substring(pos), charsToDelete));
            }
        }
        return toStringArray(result);
    }

    /**
     * collection to array
     *
     * @param collection collection
     * @return String[]
     */
    public static String[] toStringArray(Collection<String> collection) {
        return (Objects.nonNull(collection) ? collection.toArray(new String[0]) : new String[0]);
    }

    /**
     * if inString indexOf charsToDelete  is not null, inString = "abcdefg" , charsToDelete = "ag"; stop:  inString = "bcdef"
     *
     * @param inString      inString
     * @param charsToDelete charsToDelete
     * @return String
     */
    public static String deleteAny(String inString, String charsToDelete) {
        if ((!hasLength(inString)) || (!hasLength(charsToDelete))) {
            // inString or charsToDelete is null return inString
            return inString;
        }
        StringBuilder sb = new StringBuilder(inString.length());
        for (int i = 0; i < inString.length(); i++) {
            char c = inString.charAt(i);
            if (charsToDelete.indexOf(c) == -1) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * inString  indexOf oldPattern replace  newPattern
     *
     * @param inString   inString
     * @param oldPattern oldPattern
     * @param newPattern newPattern
     * @return String
     */
    public static String replace(String inString, String oldPattern, String newPattern) {
        // newPattern not null
        if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) {
            return inString;
        }
        //return oldPattern.index
        int index = inString.indexOf(oldPattern);
        if (index == -1) {
            return inString;
        }
        //if newPattern is long oldPattern
        int capacity = inString.length();
        if (newPattern.length() > oldPattern.length()) {
            capacity += 16;
        }
        StringBuilder sb = new StringBuilder(capacity);
        int pos = 0;
        int patLen = oldPattern.length();
        // the \\ replace /
        while (index >= 0) {
            //substring(pos - index)
            sb.append(inString.substring(pos, index));
            // add /
            sb.append(newPattern);
            pos = index + patLen;
            index = inString.indexOf(oldPattern, pos);
        }
        // append any characters to the right of a match
        sb.append(inString.substring(pos));
        return sb.toString();
    }

    /**
     * is str is null OR size = 0
     *
     * @param str str
     * @return boolean
     */
    public static boolean hasLength(String str) {
        return (Objects.nonNull(str) && !str.isEmpty());
    }


    public static boolean hasText(String str) {
        return (str != null && !str.isEmpty() && containsText(str));
    }

    private static boolean containsText(String str) {
        if (Objects.nonNull(str)) {
            int strLen = str.length();
            for (int i = 0; i < strLen; i++) {
                if (!Character.isWhitespace(str.charAt(i))) {
                    return true;
                }
            }
        }
        return false;
    }
}
